﻿/// <reference path = "../locales/locales.ts" />

namespace VantCellTypes {

    export interface Icon {
        Name: string;
        BuiltIn?: boolean;
        Color?: string;
        UseCellTypeForeColor: boolean;
    }

    enum CultureEnum {
        CN = "zh-CN",
        EN = "en-US",
        KR = 'ko-KR',
        JA = 'ja-JP'
    }

    enum LangPackage {
        CN = "VantZhCN",
        EN = "VantEnUS",
        KR = 'VantKoKR',
        JA = 'VantJaJP'
    }

    function internationalize() {
        const culture = CultureEnum[Forguncy.RS.Culture];
        const langPackage = LangPackage[Forguncy.RS.Culture];
        window.vant.Locale.use(culture, window[langPackage]);
    }

    internationalize();
    const pluginPath = Forguncy.Helper.SpecialPath.getPluginRootPath("EB88A8AF-2A9D-494A-95B3-CCF8DA6F5BAC");
    const touchEmulatorScriptUrl = pluginPath + "Resources/touch-emulator.js";

    function loadScript(url: string) {
        const script = document.createElement("script");
        script.type = "text/javascript";
        script.src = url;
        document.body.appendChild(script);
    }

    function getIsEmulator(): boolean {
        try {
            const { search } = window?.top?.location;
            return search && search.indexOf("isMobile=true") !== -1;
        }
        catch {
            return false;
        }
    }

    function loadTouchEmulatorScript() {
        if (getIsEmulator()) {
            loadScript(touchEmulatorScriptUrl);
        }
    }

    loadTouchEmulatorScript();

    export class VantCellTypeBase<T = object> extends Forguncy.Plugin.CellTypeBase {
        protected uId;
        protected container: JQuery;
        public vue: any;
        private _vueApp;
        protected _cellStyle: Forguncy.Plugin.StyleMetaData = {};

        protected cellType: T = <any>this.CellElement.CellType;

        public createVueApp(option: any) {
            const self = this;

            if (option.beforeCreate) {
                const beforeCreate = option.beforeCreate;

                option.beforeCreate = function () {
                    self.vue = this;
                    beforeCreate();
                };
            } else {
                option.beforeCreate = function () {
                    self.vue = this;
                };
            }

            const vueApp = Vue.createApp(option);
            vueApp.use(window.vant);
            vueApp.mount(`#${this.uId}`);
            this._vueApp = vueApp;
        }

        public updateColorVar(key: string, color: string) {
            let cssStr = `${key}:${Forguncy.ConvertToCssColor(color)};`;

            cssStr = `:root{ ${cssStr} }`;

            const style = document.createElement("style");
            style.innerHTML = cssStr;
            document.getElementsByTagName("head")[0].appendChild(style);
        }

        public setFontStyle(styleInfo: Forguncy.Plugin.StyleMetaData) {
            const currentStyleInfo = this._cellStyle;
            currentStyleInfo.FontFamily = styleInfo.FontFamily;
            currentStyleInfo.FontStyle = styleInfo.FontStyle;
            currentStyleInfo.FontSize = styleInfo.FontSize;
            currentStyleInfo.FontWeight = styleInfo.FontWeight;
            currentStyleInfo.Foreground = styleInfo.Foreground;
            currentStyleInfo.Strikethrough = styleInfo.Strikethrough;
            currentStyleInfo.Underline = styleInfo.Underline;
            this.setFontToDom();
        }

        protected setFontToDom() {
            const fontDom = this.fontDom;
            if (fontDom) {
                fontDom.css(this.getFontStyle());
            }
        }

        private getFontStyle() {
            const styleInfo = this._cellStyle ?? {};
            const textDecoration = [];
            if (styleInfo.Underline) {
                textDecoration.push("underline");
            }
            if (styleInfo.Strikethrough) {
                textDecoration.push("line-through");
            }
            return {
                "font-family": styleInfo.FontFamily ? styleInfo.FontFamily : "",
                "font-size": styleInfo.FontSize && styleInfo.FontSize > 0 ? styleInfo.FontSize : "",
                "font-style": styleInfo.FontStyle ? styleInfo.FontStyle.toLowerCase() : "",
                "font-weight": styleInfo.FontWeight ? styleInfo.FontWeight.toLowerCase() : "",
                "text-decoration": textDecoration.join(" "),
                "color": styleInfo.Foreground ? Forguncy.ConvertToCssColor(styleInfo.Foreground) : ""
            };
        }

        private _fontSelector: string;
        public get fontSelector() {
            return this._fontSelector;
        }
        public set fontSelector(value: string) {
            if (typeof value === "string") {
                this._fontSelector = value;
                const style = this.getFontStyle();
                let styleStr = "";
                Object.keys(style).forEach(key => {
                    if (style[key] !== "") {
                        let cssValue = style[key];
                        if (key === "font-size") {
                            cssValue += "px";
                        }
                        styleStr += `${key}: ${cssValue};`;
                    }
                });
                const styleElement = document.createElement("style");
                styleElement.setAttribute("type", "text/css");
                styleElement.innerHTML = `#${this.uId} ${value}, [id_temp=${this.uId}] ${value} { ${styleStr} }`;
                const container = this.container[0];
                container.insertBefore(styleElement, container.childNodes[0]);
            }
        }

        private _fontDom: JQuery;
        public get fontDom() {
            return this._fontDom;
        }

        public set fontDom(value) {
            this._fontDom = value;
            this.setFontToDom();
        }
        private static generateID(prefix = "fgc-vant") {
            return `${prefix}-${new Date().getTime().toString(36)}-${Math.random().toString(36).slice(2)}`;
        }

        public createContent() {
            VantTheme.updateCssAndAppend();

            this.uId = VantCellTypeBase.generateID();
            this.container = $(`<div id=${this.ID}><div id ='${this.uId}' style='width:100%;height:100%'></div>`)
                .css("width", "100%")
                .css("height", "100%");
            this._cellStyle = this.CellElement.StyleInfo;
            return this.container;
        }

        public addCustomClass(className) {
            this.getContainer().addClass(className);
        }

        private loop() {
            return undefined;
        }

        public setValueToElement(jElement: JQuery, value: any) {
            return (this.vue?.setValue || this.loop)(value);
        }

        public getValueFromElement() {
            return (this.vue?.getValue || this.loop)();
        }
        public disable() {
            super.disable();
            this.onIsDisabledChanged();
        }

        public enable() {
            super.enable();
            this.onIsDisabledChanged();
        }

        private onIsDisabledChanged() {
            if (!this.vue) {
                return;
            }

            if (this.isDisabled()) {
                this.vue.disable?.();
            } else {
                this.vue.enable?.();
            }
        }


        public setReadOnly(value) {
            super.setReadOnly(value);
            if (this.vue?.setReadOnly) {
                return this.vue?.setReadOnly(this.isReadOnly());
            }
        }

        public onPageLoaded(info: Forguncy.Plugin.CellTypeInfo) {
            this.setFontToDom();
            this.setReadOnly(info.isReadOnly);
            if (info.isDisabled) {
                this.disable();
            }
            else {
                this.enable();
            }
            if (this.vue?.setValue) {
                this.vue?.setValue(info.value);
            }
        }
        public calcNumber(value) {
            if (value === 0) {
                return value;
            }
            if (value) {
                if (typeof (value) === "string") {
                    value = this.evaluateFormula(value);
                }
                return Number(value);
            }
        }

        public isEmpty(v: any) {
            return v === null || v === undefined || v === "";
        }

        public formatDate(date: Date, fmt: string) {
            const o = {
                "M+": date.getMonth() + 1,
                "d+": date.getDate(),
                "H+": date.getHours(),
                "m+": date.getMinutes(),
                "s+": date.getSeconds(),
                "q+": Math.floor((date.getMonth() + 3) / 3),
                "S": date.getMilliseconds()
            };
            if (/(y+)/.test(fmt)) {
                fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
            }
            for (const k in o) {
                if (new RegExp("(" + k + ")").test(fmt)) {
                    fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
                }
            }
            return fmt;
        }

        public isValidDate(date: any) {
            return date instanceof Date && !isNaN(date.getTime());
        }
        // 给vue列表的每个子项生成不重复的key
        public uniqueKeyCreator(options: Array<any>, baseKeyPath: string = "") {
            const keyCache = new Set();

            function getUniqueKey(baseKey: any) {
                if (typeof baseKey === "object" && baseKey !== null) {
                    return baseKey;
                }
                const key = `key_${baseKey}`;
                if (keyCache.has(key)) {
                    return getUniqueKey(baseKey + "1");
                } else {
                    keyCache.add(key);
                    return key;
                }
            }

            return options.map(option => {
                const baseKey = this.isPlainObject(option) ? option[baseKeyPath] : option;
                const key = getUniqueKey(baseKey);
                return this.isPlainObject(option) ? { key, ...option } : { key, value: option };
            });
        }

        public isPlainObject(v: any) {
            return Object.prototype.toString.call(v) === "[object Object]";
        }

        public isFormula(value) {
            return !this.isEmpty(value) && value.toString()[0] === "=";
        }

        public destroy() {
            this._vueApp.unmount();
            this._fontDom = null;
            super.destroy();
        }

        public getCustomSlotByPath(slotPath: SlotPath): string {
            const slot = this.getPropertyByPath((<any>window).FgcVant, slotPath.split("."));
            let slotStr = "";
            if (slot) {
                const classNames = this.CellElement.CssClassName?.split(" ") ?? [];
                for (const name of classNames) {
                    const selectSlotFunc = slot[name];
                    if (selectSlotFunc) {
                        slotStr = selectSlotFunc();
                        slotStr = typeof slotStr === "string" ? slotStr : "";
                        break;
                    }
                }
            }

            return slotStr;
        }

        public getCustomFeatureByPath(featurePath: FeaturePath): any {
            const feature = this.getPropertyByPath((<any>window).FgcVant, featurePath.split("."));
            let featureFunc;
            if (feature) {
                const classNames = this.CellElement.CssClassName?.split(" ") ?? [];
                for (const name of classNames) {
                    const func = feature[name];
                    if (func) {
                        featureFunc = func;
                        break;
                    }
                }
            }

            return featureFunc;
        }

        public getPropertyByPath(target: any, pathes: Array<string>): any {
            let result = target ?? {};
            for (const item of pathes) {
                const property = result[item];
                if (property !== undefined) {
                    result = property;
                } else {
                    return null;
                }
            }
            return result;
        }

        public format(value: any) {
            if (this.CellElement?.StyleInfo?.["Formatter"]) {
                const formatedResult = Forguncy.FormatHelper.format(this.CellElement.StyleInfo?.["Formatter"], value);
                return formatedResult.text;
            }
            return value?.toString();
        }
    }

    export class IconHelper {
        public static getIcon(icon: Icon, callback: (result: string) => void): void {
            if (icon) {
                if (typeof (icon) === "string") {
                    let src = <string>icon;
                    if (IconHelper.isAttachment(src)) {
                        src = Forguncy.Helper.SpecialPath.getUploadImageFolderPathInServer() + encodeURIComponent(src);
                    }
                    callback(src);
                }
            }
            if (!icon?.Name) {
                return;
            }
            let src: string;
            if (icon.BuiltIn) {
                src = Forguncy.Helper.SpecialPath.getBuiltInImageFolderPath() + icon.Name;
            }
            else {
                src = Forguncy.Helper.SpecialPath.getImageEditorUploadImageFolderPath() + encodeURIComponent(icon.Name);
            }
            if (Forguncy.ImageDataHelper.IsSvg(src)) {
                const xhr = $.get(src, (data) => {
                    const svg = $(data.documentElement);
                    Forguncy.ImageHelper.preHandleSvg(svg, icon.Color);
                    callback(IconHelper.GetBase64FromSvgElement(svg[0].outerHTML));
                });
                xhr.fail(() => {
                    callback(null);
                });
            }
            else {
                callback(src);
            }
        }
        public static GetBase64FromSvgElement(svgStr: string): string {
            return 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svgStr)));
        }
        public static isAttachment(src: string): boolean {
            if (typeof src !== "string") {
                return false;
            }
            src = src.toLowerCase();
            if (src.indexOf("http") === 0) {
                return false;
            }
            if (src.length < 37 || src[36] !== "_") {
                return false;
            }
            // FORGUNCY-5372 [VideoPlayer]External video set as the FilePreviewer cell, the video cannot play in runtime
            //if (src[src.length - 1] !== "|") {
            //    return false;
            //}
            // ---------------------
            return true;
        }
    }

    export enum SlotPath {
        pickerOption = "PickerSlots.Option",
        cascaderOption = "CascaderSlots.Option",
        datetimePickerOption = "DatetimePickerSlots.Option",
        gridItemContent = "GridItemSlots.Content"
    }

    export enum FeaturePath {
        calendarFormatter = "CalendarFeature.Formatter",
        swipeItem = "SwipeFeature.Item",
        swipePreviewItem = "SwipeFeature.PreviewItem"
    }

    export interface Icon {
        Name: string;
        BuiltIn?: boolean;
        Color?: string;
    }
    export interface IInputBaseParam {
        CommandList: object[];
        label: string;
        placeholder: string;
        leftIcon: Icon;
        rightIcon: Icon;
        border: boolean;
        required: boolean;
        clearable: boolean;
        isLink: boolean;
        labelWidth: number;
        DefaultValue: any;
    }

    export class InputBase<T = object> extends VantCellTypeBase<T> {
        private _inputTextCache: string;
        public getData(cellType: IInputBaseParam) {
            return {
                value: undefined,
                placeholder: cellType.placeholder,
                border: cellType.border,
                disabled: undefined,
                readonly: undefined,
                clearable: cellType.clearable,
                isLink: cellType.isLink,
                leftIcon: null,
                rightIcon: null,
                inputAlign: "left",
                type: "text"
            };
        }

        public setFontToDom() {
            super.setFontToDom();
            if (this.vue) {
                if (this._cellStyle.HorizontalAlignment === Forguncy.Plugin.CellHorizontalAlignment.Center) {
                    this.vue.inputAlign = "center";
                }
                else if (this._cellStyle.HorizontalAlignment === Forguncy.Plugin.CellHorizontalAlignment.Right) {
                    this.vue.inputAlign = "right";
                }
                else {
                    this.vue.inputAlign = "left";
                }
            }
        }

        public getInputTemplate(moreBindingString: string) {
            return `
<div :class="border ? 'fgc-vant-field-border':''">
    <van-field
        ref="van-field"
        v-model="value"
        :placeholder="placeholder"
        :disabled="disabled"
        :clearable="type === 'textarea' ? false : (clearable && !disabled && !readonly)"
        :is-link="isLink"
        :left-icon="type === 'textarea' ? '' : leftIcon"
        :right-icon="type === 'textarea' ? '' : rightIcon"
        :input-align="inputAlign"
        center
        ${moreBindingString}
    />
</div>
`;
        }

        public getDefaultMethods(obj: object) {
            obj = obj ?? {};
            const cellType = <IInputBaseParam>this.CellElement.CellType;

            const base = {
                getValue() {
                    return this.value;
                },
                setValue(value) {
                    this.value = value;
                },
                disable() {
                    this.disabled = true;
                    this.updateIsLink();
                },
                enable() {
                    this.disabled = false;
                    this.updateIsLink();
                },
                setReadOnly(value) {
                    this.readonly = value;
                    this.updateIsLink();
                },
                updateIsLink() {
                    if (this.readonly || this.disabled) {
                        this.isLink = false;
                    }
                    else {
                        this.isLink = cellType.isLink;
                    }
                }
            };
            return { ...base, ...obj };
        }

        public setFontToInputDom(vue, dom: JQuery = null) {
            if (!dom) {
                dom = $(".van-field__control", $(vue.$el));
            }
            this.fontDom = dom;
            this.setFontToDom();
        }

        public onPageLoaded(info: Forguncy.Plugin.CellTypeInfo) {
            const cellType = <IInputBaseParam>this.CellElement.CellType;

            IconHelper.getIcon(cellType.leftIcon, icon => {
                this.vue.leftIcon = icon;
            });
            IconHelper.getIcon(cellType.rightIcon, icon => {
                this.vue.rightIcon = icon;
            });

            this._inputTextCache = this.getValueFromElement()?.toString();
            this.getContainer().keyup(() => {
                if (this._inputTextCache !== this.getValueFromElement()?.toString()) {
                    this.hideValidateTooltip();
                }
                this._inputTextCache = this.getValueFromElement()?.toString();
            });

            super.onPageLoaded(info);
        }
        public Focus() {
            this.vue.$refs["van-field"].focus();
        }
        public setFocus() {
            this.Focus();
        }
        public hasFocus() {
            const dom = $("input", this.getContainer());
            return dom.length && document.activeElement === dom[0];
        }
        public Select() {
            const input = $(this.vue.$el).find("input");
            input?.focus();
            input?.select();
        }
        public setValueToElement(jElement: JQuery, value: any) {
            super.setValueToElement(jElement, value);
            this._inputTextCache = this.getValueFromElement()?.toString();
        }
    }

    export class SupportDataSourceCellType {
        public static refreshData(cellType: Forguncy.Plugin.CellTypeBase, bindingDataSourceModel, callBack, watchOnDependenceChange: boolean = true, options: Forguncy.Plugin.queryDataOption = null, userAction = false) {
            cellType.getBindingDataSourceValue(bindingDataSourceModel, options, (dataSource) => {
                callBack(dataSource, userAction);
            });
            if (watchOnDependenceChange) {
                cellType.onDependenceCellValueChanged((userAction) => {
                    SupportDataSourceCellType.refreshData(cellType, bindingDataSourceModel, callBack, false, options, userAction);
                });
            }
        }
    }
}
